package org.mv.mm.docs;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.mv.mm.api.Doc;
import org.mv.mm.api.Fragment;
import org.mv.mm.api.capabilities.IRefreshableFragmentViewCapability;
import org.mv.mm.api.capabilities.IReloadableFragmentCapability;
import org.mv.mm.api.capabilities.ISaveableFragmentCapability;
import org.mv.mm.api.data.IDataProvider;
import org.mv.mm.common.CentralLookup;
import org.mv.mm.common.ILinkedWindow;
import org.mv.mm.docs.nodes.FragmentNode;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.cookies.SaveCookie;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.NbBundle;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//org.mv.mm.docs//ChapterEdit//EN",
autostore = false)
@TopComponent.Description(preferredID = "ChapterEditTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", 
persistenceType = TopComponent.PERSISTENCE_NEVER)
@TopComponent.Registration(mode = "editor", openAtStartup = false)
public final class FragmentEditTopComponent extends TopComponent implements LookupListener {

  private TopComponent tcOpenedFrom;
  private Lookup.Result<FragmentNode> fragmentNodeResult = null;
  private Lookup.Result<Fragment> fragmentResult = null;
  private Lookup.Result<IDataProvider> dataProviderResult = null;
  private FragmentNode fragmentNode = null;
  private Lookup.Result<Node> cNodeResult = null;
  private Fragment fragment = null;
  private IDataProvider dataProvider = null;
  private final InstanceContent content;
  private final SaveableViewCapability impl;
  private final ShowParentCookie showPar;
  private static final Logger logger = Logger.getLogger(FragmentEditTopComponent.class.getName());

  public FragmentEditTopComponent() {
    initComponents();
    setName(NbBundle.getMessage(FragmentEditTopComponent.class, "CTL_ChapterEditTopComponent"));
    setToolTipText(NbBundle.getMessage(FragmentEditTopComponent.class, "HINT_ChapterEditTopComponent"));

    fragWorkName.getDocument().addDocumentListener(new DocumentListener() {

      @Override
      public void insertUpdate(DocumentEvent arg0) {
        fire(true);
      }

      @Override
      public void removeUpdate(DocumentEvent arg0) {
        fire(true);
      }

      @Override
      public void changedUpdate(DocumentEvent arg0) {
        fire(true);
      }
    });

    //Create a new instance of our SaveCookie implementation:
    impl = new SaveableViewCapability();

    showPar = new ShowParentCookie();

    //Create a new instance of our dynamic object:
    content = new InstanceContent();

    /*
     * Add the ShowParentCookie to context, so the action to show the parent
     * window is active.
     */
    content.add(showPar);

    //Add the dynamic object to the TopComponent Lookup:
    associateLookup(new AbstractLookup(content));
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        parentChapTitle1 = new javax.swing.JTextField();
        fragWorkName = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        fragTitle = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        fragDescrip = new javax.swing.JTextArea();
        jLabel3 = new javax.swing.JLabel();
        fragAuthor = new javax.swing.JTextField();
        jLabel4 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        fragText = new javax.swing.JTextArea();
        jLabel5 = new javax.swing.JLabel();
        docName = new javax.swing.JLabel();
        fragAbbrev = new javax.swing.JTextField();
        jLabel6 = new javax.swing.JLabel();

        parentChapTitle1.setText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.parentChapTitle1.text")); // NOI18N

        fragWorkName.setText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragWorkName.text")); // NOI18N
        fragWorkName.setToolTipText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragWorkName.toolTipText")); // NOI18N
        fragWorkName.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                fragWorkNameLostFocus(evt);
            }
        });

        jLabel1.setLabelFor(fragWorkName);
        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.jLabel1.text")); // NOI18N

        fragTitle.setText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragTitle.text")); // NOI18N
        fragTitle.setToolTipText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragTitle.toolTipText")); // NOI18N

        jLabel2.setLabelFor(fragTitle);
        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.jLabel2.text")); // NOI18N

        fragDescrip.setColumns(20);
        fragDescrip.setRows(5);
        jScrollPane1.setViewportView(fragDescrip);

        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.jLabel3.text")); // NOI18N

        fragAuthor.setText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragAuthor.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.jLabel4.text")); // NOI18N

        fragText.setColumns(20);
        fragText.setRows(5);
        fragText.setToolTipText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragText.toolTipText")); // NOI18N
        jScrollPane2.setViewportView(fragText);

        org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.jLabel5.text")); // NOI18N

        docName.setFont(docName.getFont().deriveFont(docName.getFont().getStyle() | java.awt.Font.BOLD, docName.getFont().getSize()+4));
        docName.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        org.openide.awt.Mnemonics.setLocalizedText(docName, org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.docName.text")); // NOI18N

        fragAbbrev.setText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragAbbrev.text")); // NOI18N
        fragAbbrev.setToolTipText(org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.fragAbbrev.toolTipText")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(FragmentEditTopComponent.class, "FragmentEditTopComponent.jLabel6.text")); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel1)
                            .addComponent(jLabel2)
                            .addComponent(jLabel3)
                            .addComponent(jLabel4)
                            .addComponent(jLabel5))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(fragWorkName, javax.swing.GroupLayout.PREFERRED_SIZE, 149, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(jLabel6)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(fragAbbrev, javax.swing.GroupLayout.DEFAULT_SIZE, 140, Short.MAX_VALUE))
                            .addComponent(fragTitle)
                            .addComponent(fragAuthor)
                            .addComponent(jScrollPane1)
                            .addComponent(jScrollPane2)))
                    .addComponent(docName, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(docName, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(fragTitle, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(fragWorkName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel6)
                    .addComponent(fragAbbrev, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(fragAuthor, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel4)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel5)
                        .addGap(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

  private void fragWorkNameLostFocus(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_fragWorkNameLostFocus
    if (fragAbbrev.getText().isEmpty()) {
      fragAbbrev.setText(fragWorkName.getText().substring(0, 2).toUpperCase());
    }
  }//GEN-LAST:event_fragWorkNameLostFocus

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel docName;
    private javax.swing.JTextField fragAbbrev;
    private javax.swing.JTextField fragAuthor;
    private javax.swing.JTextArea fragDescrip;
    private javax.swing.JTextArea fragText;
    private javax.swing.JTextField fragTitle;
    private javax.swing.JTextField fragWorkName;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JTextField parentChapTitle1;
    // End of variables declaration//GEN-END:variables

  @Override
  public void componentOpened() {
    this.tcOpenedFrom = WindowManager.getDefault().getRegistry().getActivated();
    
    fragmentNodeResult = tcOpenedFrom.getLookup().lookupResult(FragmentNode.class);

    cNodeResult = tcOpenedFrom.getLookup().lookupResult(Node.class);
    cNodeResult.addLookupListener(this);

    fragmentResult = tcOpenedFrom.getLookup().lookupResult(Fragment.class);
    dataProviderResult = tcOpenedFrom.getLookup().lookupResult(IDataProvider.class);

    fragmentNodeResult.addLookupListener(this);
    fragmentResult.addLookupListener(this);
    dataProviderResult.addLookupListener(this);
  }

  @Override
  protected void componentShowing() {
    super.componentShowing();

    // Display detail right after opening
    resultChanged(null);
  }

  @Override
  public void componentClosed() {
    cNodeResult.removeLookupListener(this);

    fragmentNodeResult.removeLookupListener(this);
    dataProviderResult.removeLookupListener(this);
    fragmentResult.removeLookupListener(this);
  }

  @Override
  public void resultChanged(LookupEvent le) {
    //Close this T.C., when the original one, from which this one is opened, has been closed.
    //if (allNodes.isEmpty()) {
    if (!this.tcOpenedFrom.isOpened()) {
      this.close();
    } else {
      //Get the provider:
      Collection<? extends IDataProvider> allQueries = dataProviderResult.allInstances();
      Iterator<? extends IDataProvider> it1 = allQueries.iterator();
      while (it1.hasNext()) {
        dataProvider = (IDataProvider) it1.next();
      }
      //Get the fragment:
      Collection<? extends Fragment> allFragments = fragmentResult.allInstances();
      Iterator<? extends Fragment> it2 = allFragments.iterator();
      while (it2.hasNext()) {
        fragment = (Fragment) it2.next();

        
        Doc doc = fragment.getDoc();
        setDisplayName("("+doc.getAbbrev()+") " + fragment.getWorkName());
        
        docName.setText(doc.getTitle() + " (" + doc.getWorkName() + ")");

        fragAbbrev.setText(fragment.getAbbrev());
        fragWorkName.setText(fragment.getWorkName());
        fragTitle.setText(fragment.getTitle());
        fragAuthor.setText(fragment.getAuthor());
        fragDescrip.setText(fragment.getDescription());
        fragText.setText(fragment.getFragmentText());
      }
      //Get the node:
      Collection<? extends FragmentNode> allNodes = fragmentNodeResult.allInstances();

      Iterator<? extends FragmentNode> it3 = allNodes.iterator();
      while (it3.hasNext()) {
        fragmentNode = it3.next();

        //TODO je to potřeba?
        setActivatedNodes(new FragmentNode[]{fragmentNode});
        content.add(fragmentNode);

      }
    }
  }

  void writeProperties(java.util.Properties p) {
    // better to version settings since initial version as advocated at
    // http://wiki.apidesign.org/wiki/PropertyFiles
    p.setProperty("version", "1.0");
    // TODO store your settings
  }

  void readProperties(java.util.Properties p) {
    String version = p.getProperty("version");
    // TODO read your settings according to their version
  }

  public void fire(boolean modified) {
    if (modified) {
      //If the text is modified,
      //we add SaveCookie impl to Lookup:
      content.add(impl);
    } else {
      //Otherwise, we remove the SaveCookie impl from the lookup:
      content.remove(impl);
    }
  }

  private class SaveableViewCapability implements SaveCookie {

    @Override
    public void save() throws IOException {
      ISaveableFragmentCapability saveable = dataProvider.getLookup().lookup(ISaveableFragmentCapability.class);
      try {
        fragment.setAbbrev(fragAbbrev.getText());
        fragment.setWorkName(fragWorkName.getText());
        fragment.setTitle(fragTitle.getText());
        fragment.setAuthor(fragAuthor.getText());
        fragment.setDescription(fragDescrip.getText());
        fragment.setFragmentText(fragText.getText());
        saveable.save(fragment);
      } catch (Exception ex) {
        logger.log(Level.WARNING, null, ex); //TODO provide a message from Bundle
      }
      IReloadableFragmentCapability r = dataProvider.getLookup().lookup(IReloadableFragmentCapability.class);
      try {
        r.reload();
      } catch (Exception e) {
        logger.log(Level.WARNING, null, e); //TODO provide a message from Bundle
      }

      /*
       * IRefreshableFragmentViewCapability rvc =
       * fragmentNode.getLookup().lookup(IRefreshableFragmentViewCapability.class);
       * try { rvc.reloadNode(); } catch (Exception ex) {
       * logger.log(Level.WARNING, null, ex); //TODO provide a message from
       * Bundle }
       */

      CentralLookup cl = CentralLookup.getDefault();
      Collection<? extends IRefreshableFragmentViewCapability> nodes = cl.lookupAll(IRefreshableFragmentViewCapability.class);
      for (IRefreshableFragmentViewCapability rvc : nodes) {
        try {
          rvc.refreshAfterEdit(fragment);
        } catch (Exception ex) {
          logger.log(Level.WARNING, null, ex); //TODO provide a message from Bundle
        }
      }

      fire(false);
    }
  }

  private class ShowParentCookie implements ILinkedWindow {

    @Override
    public void showParent() {
      FragmentEditTopComponent.this.tcOpenedFrom.requestActive();
    }
  }
}
